﻿Ext.util.Droppable = Ext.extend(Ext.util.Observable, {
    baseCls: 'x-droppable',

    //The CSS added to a Droppable when a Draggable in the same group is being dragged. Defaults to 'x-drop-active'.
    activeCls: 'x-drop-active',

    //The CSS class to add to the droppable when dragging a draggable that is not in the same group. Defaults to 'x-drop-invalid'.
    invalidCls: 'x-drop-invalid',

    //The CSS class to add to the droppable when hovering over a valid drop. (Defaults to 'x-drop-hover')
    hoverCls: 'x-drop-hover',

    //Determines when a drop is considered 'valid' whether it simply need to intersect(相交) the region or 
    //if it needs to be contained within the region. Valid values are: 'intersects' or 'contains'
    validDropMode: 'intersect',


    disabled: false,

    //Draggable and Droppable objects can participate in a group which are capable of interacting. Defaults to 'base'
    group: 'base',


    tolerance: null,



    monitoring: false,


    constructor: function (el, config) {
        config = config || {};
        Ext.apply(this, config);

        this.addEvents(

            'dropactivate',


            'dropdeactivate',


            'dropenter',


            'dropleave',


            'drop'
        );

        this.el = Ext.get(el);
        Ext.util.Droppable.superclass.constructor.call(this);

        if (!this.disabled) {
            this.enable();
        }

        this.el.addCls(this.baseCls);
    },


    onDragStart: function (draggable, e) {
        if (draggable.group === this.group) {
            this.monitoring = true;
            this.el.addCls(this.activeCls);
            this.region = this.el.getPageBox(true);

            draggable.on({
                drag: this.onDrag,
                beforedragend: this.onBeforeDragEnd,
                dragend: this.onDragEnd,
                scope: this
            });

            if (this.isDragOver(draggable)) {
                this.setCanDrop(true, draggable, e);
            }

            this.fireEvent('dropactivate', this, draggable, e);
        }
        else {
            draggable.on({
                dragend: function () {
                    this.el.removeCls(this.invalidCls);
                },
                scope: this,
                single: true
            });
            this.el.addCls(this.invalidCls);
        }
    },


    isDragOver: function (draggable, region) {
        return this.region[this.validDropMode](draggable.region);
    },


    onDrag: function (draggable, e) {
        this.setCanDrop(this.isDragOver(draggable), draggable, e);
    },


    setCanDrop: function (canDrop, draggable, e) {
        if (canDrop && !this.canDrop) {
            this.canDrop = true;
            this.el.addCls(this.hoverCls);
            this.fireEvent('dropenter', this, draggable, e);
        }
        else if (!canDrop && this.canDrop) {
            this.canDrop = false;
            this.el.removeCls(this.hoverCls);
            this.fireEvent('dropleave', this, draggable, e);
        }
    },


    onBeforeDragEnd: function (draggable, e) {
        draggable.cancelRevert = this.canDrop;
    },


    onDragEnd: function (draggable, e) {
        this.monitoring = false;
        this.el.removeCls(this.activeCls);

        draggable.un({
            drag: this.onDrag,
            beforedragend: this.onBeforeDragEnd,
            dragend: this.onDragEnd,
            scope: this
        });


        if (this.canDrop) {
            this.canDrop = false;
            this.el.removeCls(this.hoverCls);
            this.fireEvent('drop', this, draggable, e);
        }

        this.fireEvent('dropdeactivate', this, draggable, e);
    },

    //Enable the Droppable target. This is invoked(调用) immediately after constructing a Droppable if the disabled parameter is NOT set to true.
    enable: function () {
        if (!this.mgr) {
            this.mgr = Ext.util.Observable.observe(Ext.util.Draggable);
        }
        this.mgr.on({
            dragstart: this.onDragStart,
            scope: this
        });
        this.disabled = false;
    },


    disable: function () {
        this.mgr.un({
            dragstart: this.onDragStart,
            scope: this
        });
        this.disabled = true;
    },


    isDisabled: function () {
        return this.disabled;
    },

    //Method to determine whether this Droppable is currently monitoring(监测) drag operations of Draggables.
    isMonitoring: function () {
        return this.monitoring;
    }
});